package table

import (
	

	
	
	
	
	
	
)

// Option represents an option that can be used to configure a table panel.
type Option func(table *Table) error

// AggregationType represents an aggregation function used on values returned
// by the query.
type AggregationType string

const (
	// AVG aggregates results by computing the average.
	AVG AggregationType = "avg"

	// Count aggregates results by counting them.
	Count AggregationType = "count"

	// Current aggregates results by keeping only the current value.
	Current AggregationType = "current"

	// Min aggregates results by keeping only the smallest value.
	Min AggregationType = "min"

	// Max aggregates results by keeping only the largest value.
	Max AggregationType = "max"
)

// Aggregation configures how to display an aggregate in the table.
type Aggregation struct {
	Label string
	Type  AggregationType
}

// Table represents a table panel.
type Table struct {
	Builder *sdk.Panel
}

// New creates a new table panel.
func ( string,  ...Option) (*Table, error) {
	 := &Table{Builder: sdk.NewTable()}
	 := ""

	.Builder.IsNew = false
	.Builder.TablePanel.Styles = []sdk.ColumnStyle{
		{
			Alias:   &,
			Pattern: "/.*/",
			Type:    "string",
		},
	}

	for ,  := range append(defaults(), ...) {
		if  := ();  != nil {
			return nil, 
		}
	}

	return , nil
}

func defaults() []Option {
	return []Option{
		Span(6),
		TimeSeriesToRows(),
	}
}

// Links adds links to be displayed on this panel.
func ( ...links.Link) Option {
	return func( *Table) error {
		.Builder.Links = make([]sdk.Link, 0, len())

		for ,  := range  {
			.Builder.Links = append(.Builder.Links, .Builder)
		}

		return nil
	}
}

// WithPrometheusTarget adds a prometheus target to the table.
func ( string,  ...prometheus.Option) Option {
	 := prometheus.New(, ...)

	return func( *Table) error {
		.Builder.AddTarget(&sdk.Target{
			RefID:          .Ref,
			Expr:           .Expr,
			IntervalFactor: .IntervalFactor,
			Interval:       .Interval,
			Step:           .Step,
			LegendFormat:   .LegendFormat,
			Instant:        .Instant,
			Format:         .Format,
		})

		return nil
	}
}

// WithGraphiteTarget adds a Graphite target to the table.
func ( string,  ...graphite.Option) Option {
	 := graphite.New(, ...)

	return func( *Table) error {
		.Builder.AddTarget(.Builder)

		return nil
	}
}

// WithInfluxDBTarget adds an InfluxDB target to the table.
func ( string,  ...influxdb.Option) Option {
	 := influxdb.New(, ...)

	return func( *Table) error {
		.Builder.AddTarget(.Builder)

		return nil
	}
}

// HideColumn hides the column having a label matching the given pattern.
func ( string) Option {
	return func( *Table) error {
		.Builder.TablePanel.Styles = append([]sdk.ColumnStyle{
			{
				Pattern: ,
				Type:    "hidden",
			},
		}, .Builder.TablePanel.Styles...)

		return nil
	}
}

// TimeSeriesToRows displays the data in rows.
func () Option {
	return func( *Table) error {
		.Builder.TablePanel.Transform = "timeseries_to_rows"

		return nil
	}
}

// TimeSeriesToColumns displays the data in columns.
func () Option {
	return func( *Table) error {
		.Builder.TablePanel.Transform = "timeseries_to_columns"

		return nil
	}
}

// AsJSON displays the data as JSON.
func () Option {
	return func( *Table) error {
		.Builder.TablePanel.Transform = "json"

		return nil
	}
}

// AsTable displays the data as a table.
func () Option {
	return func( *Table) error {
		.Builder.TablePanel.Transform = "table"

		return nil
	}
}

// AsAnnotations displays the data as annotations.
func () Option {
	return func( *Table) error {
		.Builder.TablePanel.Transform = "annotations"

		return nil
	}
}

// AsTimeSeriesAggregations displays the data according to the given aggregation methods.
func ( []Aggregation) Option {
	return func( *Table) error {
		 := make([]sdk.Column, 0, len())

		for ,  := range  {
			 = append(, sdk.Column{
				TextType: .Label,
				Value:    string(.Type),
			})
		}

		.Builder.TablePanel.Transform = "timeseries_aggregations"
		.Builder.TablePanel.Columns = 

		return nil
	}
}

// DataSource sets the data source to be used by the table.
func ( string) Option {
	return func( *Table) error {
		.Builder.Datasource = &sdk.DatasourceRef{LegacyName: }

		return nil
	}
}

// Span sets the width of the panel, in grid units. Should be a positive
// number between 1 and 12. Example: 6.
func ( float32) Option {
	return func( *Table) error {
		if  < 1 ||  > 12 {
			return fmt.Errorf("span must be between 1 and 12: %w", errors.ErrInvalidArgument)
		}

		.Builder.Span = 

		return nil
	}
}

// Height sets the height of the panel, in pixels. Example: "400px".
func ( string) Option {
	return func( *Table) error {
		.Builder.Height = &

		return nil
	}
}

// Description annotates the current visualization with a human-readable description.
func ( string) Option {
	return func( *Table) error {
		.Builder.Description = &

		return nil
	}
}

// Transparent makes the background transparent.
func () Option {
	return func( *Table) error {
		.Builder.Transparent = true

		return nil
	}
}